package com.hwtx.form.domain;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.annotation.IEnum;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hwtx.form.domain.def.Select;
import com.hwtx.form.domain.def.meta.config.*;
import com.hwtx.form.domain.handle.FormI18nHandle;
import com.hwtx.form.domain.handle.datamodel.DataModelDetail;
import com.hwtx.form.persistence.SQLType;
import io.geekidea.boot.auth.cache.LoginCache;
import io.geekidea.boot.framework.exception.BusinessException;
import lombok.Getter;

import java.io.IOException;
import java.util.*;

import static com.hwtx.form.domain.FormConstants.AuthElementTypeEnum.CRUD_FILTER;
import static com.hwtx.form.domain.FormConstants.AuthElementTypeEnum.PAGE;

public class FormConstants {
    public static final String FORM_ID = "formId";
    public static final String SHORT_FORM_ID = "fId";
    public static final String INPUT_FORM_VALUE_ID = "id";
    public static final String INPUT_FORM_PAGE = "pageX";
    public static final String DEFAULT_FORM_TYPE = "default";
    public static final String LOCALE_PARAM = "locale";
    public static final String PAGE_INDEX = "pageIndex";
    public static final String PAGE_SIZE = "pageSize";
    public static final String ORDER_BY_ASC = "orderByAsc";
    public static final String ORDER_BY_COLUMN = "orderByColumn";

    public static final String ROLE_FORM_HANDLE_NAME = "role";
    public static final String USER_FORM_HANDLE_NAME = "user";
    public static final String RESOURCE_FORM_HANDLE_NAME = "resource";

    public static final String ORG_FORM_HANDLE_NAME = "org";
    public static final String FORM_MANAGE_HANDLE_NAME = "innerForm";
    public static final String LOG_FORM_HANDLE_NAME = "log";
    public static final String FORM_CONFIG_HANDLE_NAME = "formConfig";
    public static final String DATA_MODEL_HANDLE_NAME = "dataModel";
    public static final String API_HANDLE_NAME = "apiConfig";

    public static final int FORM_CLASSIFY_FORM = 1;
    public static final int FORM_CLASSIFY_LIST = 2;

    public static final int RET_TYPE_LIST = 1;
    public static final int RET_TYPE_OPTION = 2;
    public static final int RET_TYPE_LIST_INCLUDE_ORG_ASSIGNED = 4;

    public static final long ORG_ROLE_FORM_ID = 13;
    public static final long USER_ROLE_TAB_FORM_ID = 14;
    public static final long DEFAULT_FORM_ID = 0;

    public static final String FIELD_POSITION_FIRST = "FIRST";

    public static final List<String> DEFAULT_PAGE_QUERY_PARAM = Lists.newArrayList(FORM_ID, PAGE_INDEX, PAGE_SIZE, ORDER_BY_COLUMN, ORDER_BY_ASC);
    public static final String OPERATION_ADD = "add";
    public static final String OPERATION_DELETE = "delete";
    public static final String OPERATION_EDIT = "edit";
    public static final String OPERATION_DELETE_BULK = "delete_bulk";
    public static final String OPERATION_SEARCH = "search";
    public static final String OPERATION_TARGET_PAGE = "target_page";
    public static final String OPERATION_TARGET_ACTION = "action";

    public static final String OPERATION_LINE = "line";
    public static final String OPERATION_HEADER = "header";
    public static final String OPERATION_HEADER_BULK = "header_bulk";
    public static final String JDBC_PREFIX = "hwtx.jdbcTemplate.";
    public static final String DEFAULT_DS_NAME = "default_ds";

    public static final int API_TEST = 1;
    public static final int API_PUBLISH = 2;

    public static final String MODEL_TYPE_SQL = "sql";

    public static final String QUERY = "query";
    public static final String FORM = "configForm";
    public static final String LIST = "list";

    public static final String HTTP_GET = "get";
    public static final String HTTP_POST = "post";

    public static final int WR_READ = 1;
    public static final String WR_WRITE_DEL = "3";
    public static final String WR_WRITE_DEL_IDS = "delIds";

    public static final String COMMON_URL = "/common";
    public static final String API_PREFIX_URL = "/common/api/";
    public static final String API_DEF_API = API_PREFIX_URL + "api-def/2";


    public static final String I18n_CACHE_KEY = "i18nMessage";
    public static final String formPrefix = "/form";
    public static final String AddOrUpdate = "/addOrUpdate";
    public static final String Get = "/get";
    public static final String Remove = "/remove";
    public static final String Update = "/update";
    public static final String Page = "/page";
    public static final String upload = "/upload";
    public static final String Add = "/add";
    public static final String List_Req = "/list";
    public static final String DEFAULT_TABLE_NAME = "default";
    public static final String AUTH_KEY = "auth";
    public static final String AUTH_ID_KEY = "authId";
    public static final String LABEL_KEY = "label";
    public static final String TITLE_KEY = "title";
    public static final String AUTH_NONE = "none";
    public static final String TYPE_KEY = "type";
    public static final String EACH_KEY = "each";
    public static final String PAGE_KEY = "page";
    public static final String URL_KEY = "url";
    public static final String CONTAINER_KEY = "container";
    public static final String WRAPPER_KEY = "wrapper";
    public static final String INIT_API_KEY = "initApi";
    public static final String API_KEY = "api";
    public static final String SCHEMA_API_KEY = "schemaApi";
    public static final String QUICK_SAVE_API_KEY = "quickSaveApi";
    public static final String QUICK_SAVE_ITEM_API_KEY = "quickSaveItemApi";
    public static final String RECEIVER_API_KEY = "receiver";
    public static final String SOURCE_API_KEY = "source";
    public static final String DELETE_API_KEY = "deleteApi";
    public static final String ADD_API_KEY = "addApi";
    public static final String EDIT_API_KEY = "editApi";

    public static final String FORM_LIST_URL = formPrefix + "/list";
    public static final String FORM_INFO_URL = formPrefix + "/listFormInfo";
    public static final String FORM_PAGE_URL = formPrefix + "/page";
    public static final List<String> LIST_URL_COLLECTION = List.of(FORM_LIST_URL, FORM_INFO_URL, FORM_PAGE_URL);
    public static final String LIST_URL_KEY = "list";
    public static final List<String> DEFAULT_URLS = List.of(formPrefix + AddOrUpdate, formPrefix + Get, formPrefix + Remove, formPrefix + Update, formPrefix + Page, formPrefix + Add, formPrefix + List_Req, formPrefix + upload);

    public static final List<UrlFindInfo> ALL_API = List.of(new UrlFindInfo(API_KEY),
            new UrlFindInfo(INIT_API_KEY), new UrlFindInfo(SCHEMA_API_KEY),
            new UrlFindInfo(QUICK_SAVE_API_KEY),
            new UrlFindInfo(QUICK_SAVE_ITEM_API_KEY),
            new UrlFindInfo(RECEIVER_API_KEY),
            new UrlFindInfo(SOURCE_API_KEY),
            new UrlFindInfo(DELETE_API_KEY),
            new UrlFindInfo(ADD_API_KEY),
            new UrlFindInfo(EDIT_API_KEY));
    public static final List<AuthElement> AUTH_ELEMENTS = List.of(
            new AuthElement(AuthElementTypeEnum.Button.type, List.of(URL_KEY), ALL_API, true),
            new AuthElement(AuthElementTypeEnum.Crud.type, List.of(new UrlFindInfo(API_KEY), new UrlFindInfo(INIT_API_KEY),
                    new UrlFindInfo(CRUD_FILTER.type + "/" + SOURCE_API_KEY),
                    new UrlFindInfo(QUICK_SAVE_API_KEY + "/" + URL_KEY),
                    new UrlFindInfo(QUICK_SAVE_ITEM_API_KEY + "/" + URL_KEY)
            ), List.of(AuthElementTypeEnum.Button.type)),
            new AuthElement(AuthElementTypeEnum.Service.type, List.of(new UrlFindInfo(API_KEY), new UrlFindInfo(SCHEMA_API_KEY)), List.of(AuthElementTypeEnum.Button.type)),
            new AuthElement(AuthElementTypeEnum.From.type,
                    List.of("url"),
                    List.of(new UrlFindInfo(API_KEY), new UrlFindInfo(INIT_API_KEY), new UrlFindInfo(SOURCE_API_KEY), new UrlFindInfo(RECEIVER_API_KEY)),
                    true,
                    List.of(AuthElementTypeEnum.Button.type),
                    List.of(AuthElementTypeEnum.Button.type)),
            new AuthElement(PAGE.type,
                    List.of("url"),
                    List.of(new UrlFindInfo(API_KEY), new UrlFindInfo(INIT_API_KEY), new UrlFindInfo(SOURCE_API_KEY), new UrlFindInfo(RECEIVER_API_KEY)),
                    true,
                    List.of(AuthElementTypeEnum.Button.type),
                    List.of(AuthElementTypeEnum.Button.type, AuthElementTypeEnum.Crud.type, AuthElementTypeEnum.Service.type, AuthElementTypeEnum.From.type)));
    public static final Map<String, DataModelDetail> DEFAULT_FIELDS = Maps.newHashMap();
    public static final String RESOURCE_NAME_PREFIX = "res-";

    static {
        DataModelDetail formDataModel = new DataModelDetail();
        formDataModel.setNum(1);
        formDataModel.setName(DefaultColumn.id.name());
        formDataModel.setDescription(DefaultColumn.id.comment);
        formDataModel.setType(SQLType.Bigint);
        formDataModel.setNotNull((byte) 1);
        formDataModel.setPriKey((byte) 1);
        formDataModel.setSys((byte) 1);
        formDataModel.setIsUnique((byte) 1);
        DEFAULT_FIELDS.put(DefaultColumn.id.name(), formDataModel);

        formDataModel = new DataModelDetail();
        formDataModel.setNum(100);
        formDataModel.setName(DefaultColumn.create_time.name());
        formDataModel.setDescription(DefaultColumn.create_time.comment);
        formDataModel.setType(SQLType.Datetime);
        formDataModel.setDefValue("CURRENT_TIMESTAMP");
        formDataModel.setNotNull((byte) 0);
        formDataModel.setPriKey((byte) 0);
        formDataModel.setSys((byte) 1);
        DEFAULT_FIELDS.put(DefaultColumn.create_time.name(), formDataModel);

        formDataModel = new DataModelDetail();
        formDataModel.setNum(101);
        formDataModel.setName(DefaultColumn.update_time.name());
        formDataModel.setDescription(DefaultColumn.update_time.comment);
        formDataModel.setType(SQLType.Datetime);
        formDataModel.setDefValue("CURRENT_TIMESTAMP");
        formDataModel.setNotNull((byte) 0);
        formDataModel.setPriKey((byte) 0);
        formDataModel.setSys((byte) 1);
        DEFAULT_FIELDS.put(DefaultColumn.update_time.name(), formDataModel);

        formDataModel = new DataModelDetail();
        formDataModel.setNum(102);
        formDataModel.setName(DefaultColumn.create_id.name());
        formDataModel.setDescription(DefaultColumn.create_id.comment);
        formDataModel.setType(SQLType.Varchar);
        formDataModel.setDefValue("");
        formDataModel.setLength(50);
        formDataModel.setNotNull((byte) 0);
        formDataModel.setPriKey((byte) 0);
        formDataModel.setSys((byte) 1);
        DEFAULT_FIELDS.put(DefaultColumn.create_id.name(), formDataModel);

        formDataModel = new DataModelDetail();
        formDataModel.setNum(103);
        formDataModel.setName(DefaultColumn.update_id.name());
        formDataModel.setDescription(DefaultColumn.update_id.comment);
        formDataModel.setType(SQLType.Varchar);
        formDataModel.setDefValue("");
        formDataModel.setLength(50);
        formDataModel.setNotNull((byte) 0);
        formDataModel.setPriKey((byte) 0);
        formDataModel.setSys((byte) 1);
        DEFAULT_FIELDS.put(DefaultColumn.update_id.name(), formDataModel);
    }

    public static List<Long> getUnChangeFormIds() {
        return Arrays.asList(ORG_ROLE_FORM_ID, USER_ROLE_TAB_FORM_ID);
    }

    public enum AuthElementTypeEnum {
        Button("button", "b"), Crud("crud", "c"), Service("service", "s"), From("form", "f"), CRUD_FILTER("filter", "cf"), PAGE("page", "p");

        @Getter
        private final String type;
        @Getter
        private final String shortName;

        AuthElementTypeEnum(String type, String shortName) {
            this.type = type;
            this.shortName = shortName;
        }

        public static String shortName(String type) {
            for (AuthElementTypeEnum value : AuthElementTypeEnum.values()) {
                if (value.getType().equals(type)) {
                    return value.getShortName();
                }
            }
            return "";
        }
    }

    public enum TplConfigKey {
        C1("c1"),
        C2("c2"),
        C3("c3"),
        R1("r1");
        @Getter
        private final String key;

        TplConfigKey(String key) {
            this.key = key;
        }

        public static TplConfigKey of(String key) {
            for (TplConfigKey value : TplConfigKey.values()) {
                if (value.getKey().equals(key)) {
                    return value;
                }
            }
            return null;
        }

        public String getAction() {
            return key + "action";
        }

        public String getInit() {
            return key + "init";
        }
    }

    public enum FormLayout {
        LAYOUT_0(0, "列表"),
        LAYOUT_1(1, "1列"),
        LAYOUT_2(2, "2列"),
        LAYOUT_3(3, "3列"),
        LAYOUT_4(4, "一行2列"),
        LAYOUT_5(5, "一行3列");
        @Getter
        private final int code;
        @Getter
        private final String desc;

        FormLayout(int code, String desc) {
            this.code = code;
            this.desc = desc;
        }

        public static FormLayout of(int code) {
            for (FormLayout value : FormLayout.values()) {
                if (value.getCode() == code) {
                    return value;
                }
            }
            return null;
        }

        public static boolean isList(Integer layout) {
            return Objects.equals(layout, LAYOUT_0.code);
        }
    }

    @Getter
    public enum Status {
        VALID(1, "有效"), INVALID(0, "无效");
        private final int code;
        private final String desc;

        Status(int code, String desc) {
            this.code = code;
            this.desc = desc;
        }

        public static Status of(int code) {
            for (Status status : Status.values()) {
                if (status.getCode() == code) {
                    return status;
                }
            }
            throw new IllegalArgumentException("No matching Status for [" + code + "]");
        }
    }

    @Getter
    public enum OperatorType {
        EQ("=", "等于"), NOT_EQ("!=", "不等于"), LIKE("like", "模糊匹配"), LEFT_LIKE("%", "左模糊匹配"), RIGHT_LIKE("%", "右模糊匹配"), GT(">", "大于"), GE(">=", "大于等于"), LT("<", "小于"), LE("<=", "小于等于"), IS_NULL("is null", "为空"), IS_NOT_NULL("is not null", "非空"), IN("in", "包含"), NOT_IN("not in", "不包含"), ANY("any", "任意值");

        private final String symbol;
        private final String desc;

        OperatorType(String symbol, String desc) {
            this.symbol = symbol;
            this.desc = desc;
        }

        public static OperatorType of(String symbol) {
            for (OperatorType type : OperatorType.values()) {
                if (type.getSymbol().equals(symbol)) {
                    return type;
                }
            }
            return null;
        }
    }


    @Getter
    public enum SqlFunType {
        SUM("sum", "求和"), MAX("max", "最大值"), MIN("min", "最小值"), COUNT("count", "计数"), AVG("avg", "平均值"), STDDEV("stddev", "标准差"), VAR_SAMP("var_samp", "样本方差"), VAR_POP("var_pop", "总体方差");

        private final String symbol;
        private final String desc;

        SqlFunType(String symbol, String desc) {
            this.symbol = symbol;
            this.desc = desc;
        }

        public static SqlFunType of(String symbol) {
            for (SqlFunType type : SqlFunType.values()) {
                if (type.getSymbol().equals(symbol)) {
                    return type;
                }
            }
            throw new IllegalArgumentException("No matching SqlFunType for [" + symbol + "]");
        }
    }

    @Getter
    public enum FormDetailOperation {
        ADD(OPERATION_ADD, "#i18n{add}", "新增", OPERATION_HEADER, true), DELETE(OPERATION_DELETE, "#i18n{delete}", "删除", OPERATION_LINE, true), EDIT(OPERATION_EDIT, "#i18n{edit}", "编辑", OPERATION_LINE, true), DELETE_BULK(OPERATION_DELETE_BULK, "#i18n{bat.delete}", "批量删除", OPERATION_HEADER, true), SEARCH(OPERATION_SEARCH, "#i18n{search}", "搜索", OPERATION_HEADER, true), TARGET_PAGE(OPERATION_TARGET_PAGE, "#i18n{target.page}", "目标页", OPERATION_HEADER, false), ACTION(OPERATION_TARGET_ACTION, "#i18n{target.action}", "动作请求", OPERATION_HEADER, false);

        private final String value;
        private final String desc;
        private final String label;
        private final String apply;
        private final boolean system;

        FormDetailOperation(String value, String label, String desc, String apply, boolean system) {
            this.value = value;
            this.label = label;
            this.desc = desc;
            this.apply = apply;
            this.system = system;
        }

        public static FormDetailOperation of(String value) {
            for (FormDetailOperation op : FormDetailOperation.values()) {
                if (op.getValue().equals(value)) {
                    return op;
                }
            }
            throw new IllegalArgumentException("No matching FormDetailOperation for [" + value + "]");
        }

        public static List<Select.Option> option() {
            return Arrays.stream(values()).map(op -> {
                Select.Option operation = new Select.Option();
                operation.setValue(op.getValue());
                operation.setLabel(FormI18nHandle.getValue(op.getLabel()));
                return operation;
            }).toList();
        }

    }

    @Getter
    public enum FormConfigType {
        QUERY(1, "query", "查询配置"), LIST(2, "list", "列表配置"), FORM(3, "configForm", "表单配置");
        private final Integer value;
        private final String desc;
        private final String name;

        FormConfigType(Integer value, String name, String desc) {
            this.value = value;
            this.desc = desc;
            this.name = name;
        }

        public static FormConfigType of(int value) {
            for (FormConfigType type : FormConfigType.values()) {
                if (type.getValue() == value) {
                    return type;
                }
            }
            throw new BusinessException("无法获取表单配置类型，value = " + value);
        }

        public static FormConfigType of(String name) {
            for (FormConfigType type : FormConfigType.values()) {
                if (type.getName().equals(name)) {
                    return type;
                }
            }
            throw new BusinessException("无法获取表单配置类型，name = " + name);
        }
    }

    @Getter
    public enum FormComponentType {

        FORM_COM_SINGLE_TEXT(1, "单行文本", "single.line.text"),
        FORM_COM_PWD(2, "密码文本", "password.text"),
        FORM_COM_MULTI_TEXT(3, "多行文本", "multi.line.text"),
        FORM_COM_RICH_TEXT(4, "富文本", "rich.text"),
        FORM_COM_DIGITAL_INPUT(5, "数字输入框", "digital.input.box"),
        FORM_COM_SINGLE_SELECT(6, "下拉框", "drop.down.box", SpringUtil.getBean(SelectComponentConfig.class)),
        FORM_COM_MUTIL_SELECT(7, "下拉多选框", "pull.down.checkbox"),
        FORM_COM_RADIO(8, "单选框", "radio.box"),
        FORM_COM_CHECK_BOX(9, "复选框", "checkbox"),
        FORM_COM_PHONE(10, "手机", "phone"),
        FORM_COM_EMAIL(11, "邮箱", "email"),
        FORM_COM_TEXT(12, "文本", "text"),
        FORM_COM_FILE(13, "文件", "file"),
        FORM_COM_CHAINED_SELECT(14, "级联下拉框", "chained.select", SpringUtil.getBean(ChainSelectFormComponentConfig.class)),
        FORM_COM_DATE(17, "日期", "date"),
        FORM_COM_DATE_TIME(18, "日期和时间", "date.and.time"),
        FORM_COM_HIDDEN(19, "隐藏", "hidden"),
        FORM_COM_CODE_EDITOR(20, "代码编辑器", "code.editor"),
        FORM_COM_IMAGE(21, "图片", "image"),
        FORM_COM_2_GROUP_CHAINED_SELECT(22, "二级级联下拉框组", "2.group.chained.select", SpringUtil.getBean(GroupChainSelectFormComponentConfig.class)),
        FORM_COM_3_GROUP_CHAINED_SELECT(23, "三级级联下拉框组", "3.group.chained.select", SpringUtil.getBean(GroupChainSelectFormComponentConfig.class)),
        FORM_COM_4_GROUP_CHAINED_SELECT(24, "四级联下拉框组", "4.group.chained.select", SpringUtil.getBean(GroupChainSelectFormComponentConfig.class)),
        FORM_COM_API_INVOKE(25, "api调用", "api.invoke", SpringUtil.getBean(ApiSelectComponentConfig.class)),
        LINE_CHART(26, "折线图", "line.chart"),
        PIE_CHART(27, "饼图", "pie.chart");

        private final int value;
        private final String desc;
        private final String i18n;
        private FormComponentConfig config;

        FormComponentType(int value, String desc, String i18n) {
            this.value = value;
            this.desc = desc;
            this.i18n = i18n;
        }

        FormComponentType(int value, String desc, String i18n, FormComponentConfig config) {
            this.value = value;
            this.desc = desc;
            this.i18n = i18n;
            this.config = config;
        }


        public static FormComponentType of(int value) {
            for (FormComponentType type : FormComponentType.values()) {
                if (type.getValue() == value) {
                    return type;
                }
            }
            return null;
        }
    }

    @Getter
    public enum FormComSelectType {
        FORM_COM_SELECT_DICT(1, "字典"), FORM_COM_SELECT_CUSTOM_LINK(3, "自定义链接");

        private final int value;
        private final String desc;

        FormComSelectType(int value, String desc) {
            this.value = value;
            this.desc = desc;
        }

        public static FormComSelectType of(int value) {
            for (FormComSelectType type : FormComSelectType.values()) {
                if (type.getValue() == value) {
                    return type;
                }
            }
            throw new IllegalArgumentException("No matching constant for [" + value + "]");
        }
    }

    @Getter
    public enum DefaultColumn {
        create_time("创建时间"), create_id("创建人"), update_time("最后修改时间"), update_id("修改人"), id("主键");
        final String comment;

        DefaultColumn(String comment) {
            this.comment = comment;
        }

        public static Map<String, Object> getCreateDefaultColumns() {
            Map<String, Object> ret = new LinkedHashMap<>();
            ret.put(create_time.name(), new Date());
            ret.put(create_id.name(), LoginCache.get().getUsername());
            ret.put(update_time.name(), new Date());
            ret.put(update_id.name(), LoginCache.get().getUsername());
            return ret;
        }

        public static List<String> getDefaultColumns() {
            return List.of(create_time.name(), create_id.name(), update_time.name(), update_id.name());
        }

        public static Map<String, Object> getModifyDefaultColumns() {
            Map<String, Object> ret = new LinkedHashMap<>();
            ret.put(update_time.name(), new Date());
            ret.put(update_id.name(), LoginCache.get() != null ? LoginCache.get().getUsername() : "system");
            return ret;
        }
    }

    public enum JoinType {
        JOIN, LEFT_JOIN, RIGHT_JOIN;

        public static JoinType of(String value) {
            for (JoinType type : JoinType.values()) {
                if (type.name().equalsIgnoreCase(value)) {
                    return type;
                }
            }
            return null;
        }
    }

    public enum DataPermScope {

        NO_DATA_PERMISSIONS(0), PERSONAL_DATA_PERMISSIONS(1), SPECIFY_ORG_DATA_PERMISSIONS(2), ORG_DATA_PERMISSIONS(3), ORG_AND_FOLLOWING_DATA_PERMISSIONS(4), ALL_DATA_PERMISSIONS(5);
        @Getter
        private final int value;

        DataPermScope(int value) {
            this.value = value;
        }

        public static DataPermScope of(int value) {
            for (DataPermScope type : DataPermScope.values()) {
                if (type.getValue() == value) {
                    return type;
                }
            }
            return null;
        }
    }


    @JsonSerialize(using = ApiRetType.CustomEnumSerializer.class)
    @JsonDeserialize(using = ApiRetType.CustomEnumDeserializer.class)
    public enum ApiRetType implements IEnum<Integer> {
        Boolean(0), LIST(1), Select(2), Chained_Select(3), Select_Label(4), GROUP_SELECT_CHAIN(5), Map(6);
        @Getter
        private final Integer value;

        ApiRetType(Integer value) {
            this.value = value;
        }

        public static ApiRetType of(Integer value) {
            for (ApiRetType type : ApiRetType.values()) {
                if (type.getValue().equals(value)) {
                    return type;
                }
            }
            return null;
        }

        static class CustomEnumSerializer extends StdSerializer<ApiRetType> {
            public CustomEnumSerializer() {
                super(ApiRetType.class);
            }

            @Override
            public void serialize(ApiRetType value, JsonGenerator gen, SerializerProvider provider) throws IOException {
                gen.writeNumber(value.getValue());
            }
        }

        // 自定义反序列化器
        static class CustomEnumDeserializer extends StdDeserializer<ApiRetType> {
            public CustomEnumDeserializer() {
                super(ApiRetType.class);
            }

            @Override
            public ApiRetType deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                int value = p.getIntValue();
                return ApiRetType.of(value);
            }
        }
    }

    @Getter
    public static class AuthElement {
        public static final int findByType = 1;
        public static final int findByName = 2;

        private final String name;
        private final List<String> fields;
        private final List<UrlFindInfo> urlNames;
        private final boolean accessInner;
        private final List<String> stopNames;
        private final List<String> innerStopNames;

        public AuthElement(String name, List<UrlFindInfo> urlNames, List<String> stopNames) {
            this(name, List.of(URL_KEY), urlNames, false, stopNames, null);
        }

        public AuthElement(String name, List<String> fields, List<UrlFindInfo> urlNames, boolean accessInner) {
            this(name, fields, urlNames, accessInner, null, null);
        }

        public AuthElement(String name, List<UrlFindInfo> urlNames, boolean accessInner, List<String> stopNames) {
            this(name, List.of(URL_KEY), urlNames, accessInner, stopNames, null);
        }

        public AuthElement(String name, List<String> fields, List<UrlFindInfo> urlNames, boolean accessInner, List<String> stopNames, List<String> innerStopNames) {
            this.name = name;
            this.fields = fields;
            this.urlNames = urlNames;
            this.accessInner = accessInner;
            this.stopNames = stopNames;
            this.innerStopNames = innerStopNames;
        }
    }

    @Getter
    public static class UrlFindInfo {
        String name;
        int findType;

        public UrlFindInfo(String name) {
            this(name, AuthElement.findByType);
        }

        public UrlFindInfo(String name, int findType) {
            this.name = name;
            this.findType = findType;
        }
    }
}